home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Demos / Evatac Software / Preditor 3.0 / Tools / Language Module Builder / Sources / AScriptParse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-16  |  14.2 KB  |  755 lines  |  [TEXT/TCEd]

  1.  /************************************************************
  2.  
  3.     AScriptParse.c
  4.     C Source to Preditor 3
  5.  
  6.     Language Module Code for the "AppleScript" language
  7.  
  8.     © Copyright Evatac Software  1988-1996
  9.     All rights reserved
  10.  
  11. ************************************************************/
  12.  
  13. #include "AScriptParse.h"
  14. #include <SetupA4.h>
  15. #include <MixedMode.h>
  16. #include <Ctype.h>
  17.  
  18. #ifndef THINKC
  19. #include <A4Stuff.h>
  20. #else
  21. #define SetCurrentA4()    0; RememberA4()
  22. #define SetA4(x)        SetUpA4()
  23. #endif
  24.  
  25. #ifdef powerc
  26. ProcInfoType __procinfo = LanguageUPPInfo;
  27. #endif
  28.  
  29. static languageGlobals            globals;
  30. static ExternalCallbackBlock    *callbacks;
  31.  
  32.  
  33. /*
  34.  * * * *     APPLESCRIPT LANGUAGE INDENT HANDLER       * * * * * *
  35.  */
  36.  
  37. static long _languageConvertToTabs(
  38.     Char    *text,
  39.     long     length,
  40.     long    hardTab
  41.     )
  42. {
  43.     int        tabs   = length / hardTab;
  44.     int        spaces = length % hardTab;
  45.     int        newLen = tabs + spaces;
  46.  
  47.     while (tabs-- > 0)
  48.         *(text++) = 9;
  49.     while (spaces-- > 0)
  50.         *(text++) = ' ';
  51.  
  52.     return(newLen);
  53. }
  54.  
  55. /*
  56.  * _languageHandleIndent
  57.  *
  58.  * Indent the selected lines according to the buffer indentation settings
  59.  */
  60. static void _languageHandleIndent(
  61.     void        *extData
  62.     )
  63. {
  64.     long        anchor, end, pos, length;
  65.     long        lineStart;
  66.     long        i, x, newPos = -1;
  67.     long        lineNumber, endLineNumber, leading;
  68.     short        spacesPerTab, hardTab;
  69.     Char        text[256];
  70.     
  71.     extGetSelection(callbacks, &anchor, &end);
  72.  
  73.     if (anchor > end) {
  74.         pos = anchor; anchor = end; end = pos;   /* Swap */
  75.     }
  76.     
  77.     lineNumber    = extLineFromPosition(callbacks, anchor);
  78.     endLineNumber = extLineFromPosition(callbacks, end);
  79.  
  80.     /*
  81.      * Indent each line in the selection
  82.      */
  83.      
  84.     while (lineNumber <= endLineNumber) {
  85.         
  86.         if (lineNumber <= 1) {
  87.             lineNumber++;
  88.             continue;
  89.         }
  90.         
  91.         leading  = extGetLeading(callbacks, lineNumber, &length,
  92.                                    &spacesPerTab, &hardTab);
  93.     
  94.         lineStart = extLineToPosition(callbacks, lineNumber);
  95.         
  96.         /*
  97.          * Select the leading spaces/tabs
  98.          */
  99.          
  100.         extSetSelection(callbacks, lineStart, lineStart + length);
  101.  
  102.         /*
  103.          * Scan back previous lines for a line that we can relate to
  104.          */
  105.  
  106.         x = 1;
  107.  
  108.         for (;;) {
  109.  
  110.             if (lineNumber - x < 1)
  111.                 break;
  112.  
  113.             leading  = extGetLeading(callbacks, lineNumber - x, &length,
  114.                                        &spacesPerTab, &hardTab);
  115.                                        
  116.             end      = extLineEnd(callbacks, lineNumber - x);
  117.             pos         = extLineToPosition(callbacks, lineNumber - x);
  118.             
  119.             /* Skip Blank lines */
  120.  
  121.             if (length == (end - pos)) {
  122.                 x++;
  123.                 continue;
  124.                }
  125.             
  126.             i = pos + length;
  127.             
  128.             /*
  129.              * Perform Indention Smarts (Still under development)
  130.              */
  131.             
  132.             extScanContents(callbacks, i);
  133.             
  134.         /*    while (i++ < end && extNextScanCharacter(callbacks, &ch)) {
  135.                 
  136.                 if (ch == '{') {
  137.                     leading += spacesPerTab;
  138.                     break;
  139.                 }
  140.             } */
  141.             
  142.             extDoneScan(callbacks);
  143.  
  144.         
  145.             /*
  146.               * Indent the line
  147.              */
  148.             
  149.             i = _languageConvertToTabs(text, leading, hardTab); 
  150.         
  151.             extInsert(callbacks, text, i);
  152.             
  153.             if (newPos == -1)
  154.                 newPos = lineStart + i;
  155.             break;
  156.         }
  157.         
  158.         lineNumber++;
  159.     }
  160.  
  161.     if (newPos >= 0)
  162.         extSetSelection(callbacks, newPos, newPos);
  163. }
  164.  
  165. /*
  166.  * * * *     APPLESCRIPT LANGUAGE PARSER       * * * * * *
  167.  */
  168.  
  169. /*
  170.  * _languageBuildString
  171.  *
  172.  * Build up a literal string or literal contant "foo" or 'foo'
  173.  */
  174. static void _languageBuildString(
  175.     languageToken            *token,
  176.     int                        c
  177.     )
  178. {
  179.     Int32    index = 1, size = kTokenStringSize;
  180.     int        origC = c;
  181.     
  182.     token->string[1]     = c;
  183.     token->type = (c == '\"' ? kSymbolStringLiteral : kSymbolCharConstant);
  184.     
  185.     if (c == 'l' || c == 'L') {
  186.         
  187.         c = languageGetChar(&globals, callbacks);
  188.         token->string[0] = c;
  189.         index = 2;
  190.     }
  191.     
  192.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  193.         
  194.         if (index < size)
  195.             token->string[++index] = c;
  196.         
  197.         if (c == origC)
  198.             break;
  199.         
  200.         else if (c == '\\') {
  201.         
  202.             c = languageGetChar(&globals, callbacks);
  203.             
  204.             if (c != -1) {
  205.                 
  206.                 if (index < size)
  207.                     token->string[++index] = c;
  208.             }
  209.         }
  210.     }
  211.     
  212.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  213.     token->string[++index] = 0;
  214. }
  215.  
  216. /*
  217.  * _languageBuildWhiteSpace
  218.  *
  219.  * Build up a directive (i.e. #define, etc)
  220.  */
  221. static void _languageBuildWhiteSpace(
  222.     languageToken             *token,
  223.     int                     c
  224.     )
  225. {
  226.     token->type = kSymbolWhiteSpace;
  227.  
  228.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  229.         
  230.         if (c != ' ' && c != '\t' && c != '\v' && c != '\n' &&
  231.             c != '\r' && c != '\f' && c != '\b') {
  232.     //    if (!isspace(c)) {
  233.             languageUngetChar(&globals, c);
  234.               return;
  235.         }
  236.     }
  237. }
  238.  
  239. /*
  240.  * _languageBuildComment
  241.  *
  242.  */
  243. static void _languageBuildComment(
  244.     languageToken             *token,
  245.     int                     c
  246.     )
  247. {
  248.     token->type                 = kSymbolComment;
  249.     globals.startLastComment     = globals.position;
  250.  
  251.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  252.     
  253.         if (c == 13)
  254.             break;
  255.     }
  256. }
  257.  
  258. /*
  259.  * _languageBuildNumber
  260.  *
  261.  */
  262. static void _languageBuildNumber(
  263.     languageToken             *token,
  264.     int                     c
  265.     )
  266. {
  267.     token->type = kSymbolIntConstant;
  268.  
  269.     if (c == '0') {
  270.     
  271.         c = languageGetChar(&globals, callbacks);
  272.  
  273.         if (c == 'x' || c == 'X') {
  274.         
  275.             while ((c = languageGetChar(&globals, callbacks)) != -1) {
  276.  
  277.                 if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
  278.                     ;
  279.                 else
  280.                     break;
  281.             }
  282.         }
  283.    
  284.         else {
  285.         
  286.             while (c != -1) {
  287.     
  288.                 if (c >= '0' && c <= '7')
  289.                     ;
  290.                 else
  291.                     break;
  292.         
  293.                 c = languageGetChar(&globals, callbacks);
  294.             }
  295.         }
  296.     }
  297.     
  298.     else {                                    /* decimal */
  299.  
  300.         while ((c = languageGetChar(&globals, callbacks)) != -1) {
  301.  
  302.             if (c >= '0' && c <= '9') 
  303.                 ;
  304.             else
  305.                 break;
  306.         }
  307.  
  308.         if (c == '.') {
  309.             
  310.             token->type = kSymbolFloatConstant;
  311.  
  312.             while ((c = languageGetChar(&globals, callbacks)) != -1) {
  313.             
  314.                 if (c >= '0' && c <= '9')
  315.                     ;
  316.                  else
  317.                     break;
  318.             }
  319.         }
  320.  
  321.         if (c == 'e' || c == 'E') {
  322.         
  323.             token->type = kSymbolFloatConstant;
  324.  
  325.             c = languageGetChar(&globals, callbacks);
  326.  
  327.             if (c == '-' || c == '+')
  328.                 c = languageGetChar(&globals, callbacks);
  329.  
  330.             while (c != -1) {
  331.  
  332.                 if (c >= '0' && c <= '9')
  333.                     ;
  334.                 else
  335.                     break;
  336.  
  337.                 c = languageGetChar(&globals, callbacks);
  338.             }
  339.         }
  340.     }
  341.  
  342.     while (c != -1) {
  343.         
  344.         if (c == 'l' || c == 'L' || c == 'u' || c == 'U' ||
  345.             c == 'f' || c == 'F' || c == 'h' || c == 'H')    
  346.             ;
  347.         else
  348.             break;
  349.         
  350.         c = languageGetChar(&globals, callbacks);
  351.     }
  352.     
  353.     if (c != -1)
  354.         languageUngetChar(&globals, c);
  355. }
  356.  
  357. /*
  358.  * _languageBuildWord
  359.  *
  360.  *
  361.  */
  362. static void _languageBuildWord(
  363.     languageToken             *token,
  364.     int                     c
  365.     )
  366. {
  367.     Int32            index = 1, size = kTokenStringSize;
  368.     Char            *scan;
  369.     
  370.     token->type = kSymbolIdentifier;
  371.  
  372.     token->string[1] = c;
  373.     
  374.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  375.  
  376.         if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'
  377.             || c >= '0' && c <= '9') {
  378.         
  379.             if (index < size)
  380.                 token->string[++index] = c;
  381.         }
  382.         else {
  383.         
  384.             languageUngetChar(&globals, c);
  385.             break;
  386.         }
  387.     }
  388.  
  389.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  390.     token->string[++index] = 0;
  391.  
  392.     if (!languageHasTable(&globals)) {
  393.         
  394.         scan = token->string + 1;
  395.         
  396.         if (languageCStringCompare(scan, (Char *) "on") == 0)
  397.             token->type = kSymbolReservedWord;
  398.         
  399.         return;
  400.     }
  401.     
  402.     else if (languageTableLookup((&globals), token->string + 1))
  403.         token->type = kSymbolReservedWord;
  404.     else if (languageCustomTableLookup((&globals), token->string + 1))
  405.         token->type = kSymbolCustomWord;
  406. }
  407.  
  408. /*
  409.  * _languageGetNextToken
  410.  */
  411. static languageToken *_languageGetNextToken(void)
  412. {
  413.     int                     first, second;
  414.     Int16                    previousType;
  415.     languageToken            *token = &globals.token;
  416.    
  417.     previousType            = token->type;
  418.     token->startLocation     = globals.position;
  419.     token->majorType        = -1;
  420.  
  421.     if ((first = languageGetChar(&globals, callbacks)) == -1)
  422.         return(nil);
  423.  
  424.     token->type             = first;
  425.  
  426.     second = languagePeekChar(&globals, callbacks);
  427.     
  428.     switch(first) {
  429.  
  430. /* "strings" */
  431. /* 'character constants' */
  432.  
  433.     case '\"':
  434.     case '\'':
  435.         _languageBuildString(token, first);
  436.         break;
  437.  
  438. /* white space */
  439.  
  440.     case ' ': case '\t': case '\v': case '\n': case '\r': case '\f': case '\b':
  441.         _languageBuildWhiteSpace(token, first);
  442.         break;
  443.  
  444. /* monographs */
  445.     case ';':
  446.         globals.startLastComment = -1;
  447.     case '(':
  448.     case '#':
  449.     case ')':
  450.     case '[':
  451.     case ']':
  452.     case '}':
  453.     case '~':
  454.     case '\\':
  455.     case ',':
  456.     case '?':
  457.     case '/':
  458.       break;
  459.  
  460. /* *, *= */
  461.  
  462.     case '*':
  463.         if (second == '=') {
  464.             languageGetChar(&globals, callbacks);
  465.              token->type = kSymbolMultiplyAssign;
  466.          }
  467.      break;
  468.  
  469. /* %, %= */
  470.  
  471.     case '%':
  472.         if (second == '=') {
  473.             languageGetChar(&globals, callbacks);
  474.               token->type = kSymbolModAssign;
  475.         }
  476.         break;
  477.  
  478. /* !, != */
  479.  
  480.     case '!':
  481.            if (second == '=') {
  482.             languageGetChar(&globals, callbacks);
  483.               token->type = kSymbolNotEqual;
  484.         }
  485.         break;
  486.  
  487. /* &, &=, && */
  488.  
  489.     case '&':
  490.         if (second == '=') {
  491.             languageGetChar(&globals, callbacks);
  492.             token->type = kSymbolAndAssign;
  493.         }
  494.         else if (second == '&') {
  495.             languageGetChar(&globals, callbacks);
  496.             token->type = kSymbolAndAnd;
  497.         }
  498.         break;
  499.  
  500. /* |, ||, |= */
  501.  
  502.     case '|':
  503.         if (second == '=') {
  504.             languageGetChar(&globals, callbacks);
  505.             token->type = kSymbolOrAssign;
  506.         }
  507.            else if (second == '|') {
  508.             languageGetChar(&globals, callbacks);
  509.             token->type = kSymbolOrOr;
  510.         }
  511.     break;
  512.  
  513. /* +, ++, += */
  514.  
  515.     case '+':
  516.         if (second == '=') {
  517.             languageGetChar(&globals, callbacks);
  518.             token->type = kSymbolPlusAssign;
  519.         }
  520.         break;
  521.  
  522. /* -, --, -=, ->, ->* */
  523.  
  524.     case '-':
  525.         if (second == '-') {        /* Comment */
  526.             _languageBuildComment(token, first);
  527.         }
  528.         else if (second == '=') {
  529.             languageGetChar(&globals, callbacks);
  530.             token->type = kSymbolMinusAssign;
  531.         }
  532.         else if (second == '>') {
  533.             languageGetChar(&globals, callbacks);
  534.             second = languagePeekChar(&globals, callbacks);
  535.  
  536.             if (second == '*') {
  537.                 languageGetChar(&globals, callbacks);
  538.                 token->type = kSymbolPointerStar;
  539.             }
  540.             else
  541.                 token->type = kSymbolPointer;
  542.         }
  543.         break;
  544.  
  545. /* ., .*, .NUM */
  546.  
  547.     case '.':
  548.         if (second == '*') {
  549.             languageGetChar(&globals, callbacks);
  550.             token->type = kSymbolDotStar;
  551.         }
  552.         
  553.         else if (second >= '0' && second <= '9')
  554.             _languageBuildNumber(token, first);
  555.             
  556.         else if (second == '.') {
  557.         
  558.             languageGetChar(&globals, callbacks);
  559.             
  560.             if (languagePeekChar(&globals, callbacks) == '.') {
  561.                 languageGetChar(&globals, callbacks);
  562.                 token->type = kSymbolEllipsis;
  563.              }
  564.              else {
  565.                  languageUngetChar(&globals, second);
  566.             }
  567.         }
  568.         break;
  569.  
  570. /* =, == */
  571.  
  572.     case '=':
  573.         if (second == '=') {
  574.             languageGetChar(&globals, callbacks);
  575.             token->type = kSymbolEqual;
  576.         }
  577.         break;
  578.  
  579. /* <, <<, <=, <<= */
  580.  
  581.     case '<':
  582.         if (second == '=') {
  583.             languageGetChar(&globals, callbacks);
  584.             token->type = kSymbolLessOrEqual;
  585.         }
  586.         else if (second == '>') {
  587.             languageGetChar(&globals, callbacks);
  588.             token->type = kSymbolNotEqual;
  589.         }
  590.         break;
  591.  
  592. /* >, >=, >>, >>= */
  593.  
  594.     case '>':
  595.         if (second == '=') {
  596.             languageGetChar(&globals, callbacks);
  597.             token->type = kSymbolGreaterOrEqual;
  598.         }
  599.         break;
  600.  
  601. /* ^, ^= */
  602.  
  603.     case '^':
  604.       if (second == '=') {
  605.           languageGetChar(&globals, callbacks);
  606.           token->type = kSymbolXOrAssign;
  607.     }
  608.       break;
  609.  
  610. /* :, := */
  611.  
  612.     case ':':
  613.         if (second == ':') {
  614.             languageGetChar(&globals, callbacks);
  615.               token->type = kSymbolAssign;
  616.         }
  617.         break;
  618.  
  619. /* the rest */
  620.  
  621.     default:
  622.         if (first >= '0' && first <= '9')
  623.             _languageBuildNumber(token, first);
  624.         else if (first >= 'a' && first <= 'z' || first >= 'A' && first <= 'Z' ||
  625.                  first == '_')
  626.                _languageBuildWord(token, first);
  627.  
  628.         /* Something weird, let the parser decide. */
  629.  
  630.         break;
  631.     }
  632.  
  633.     token->endLocation    = globals.position;
  634.     
  635.     return(token);
  636. }
  637.  
  638. void languageMain(
  639.     ExternalCallbackBlock    *extCallbacks,
  640.     WindowRef                window,
  641.     long                    options,
  642.     void                    *extData
  643.     );
  644.     
  645. /*
  646.  * languageMain
  647.  *
  648.  * This is the main entrypoint to the CODE module of a language module.
  649.  * The following operations are defined:
  650.  *
  651.  *     kLanguageParse        Parse the source file, returning positions of all tokens
  652.  *                        in the file.
  653.  *  kLanguageFunctions    Parse the source file, returning the position of just the
  654.  *                        functions in the source file
  655.  *  kLanguageIncludes    Parse the source file, returning the #include files
  656.  *  kLanguageTemplate    Expand macro -- insert template
  657.  *  kLanguageIndentLine
  658.  *    kLanguageElectric    Handle electric characters (i.e. }, {, ; )
  659.  */
  660.  
  661. void main(
  662.     ExternalCallbackBlock    *extCallbacks,
  663.     WindowRef                window,
  664.     long                    options,
  665.     void                    *extData
  666.     )
  667. {
  668.     languageToken        *token;
  669.     Int16                type;
  670.     Char                *ptr;
  671.     long                 saved_a4;
  672.  
  673.     saved_a4 = SetCurrentA4();
  674.  
  675.     languageInit(&globals, extCallbacks, options);
  676.  
  677.     callbacks    = extCallbacks;
  678.  
  679.     if (options == kLanguageTemplate) {
  680.  
  681.         languageDefaultHandler(&globals, callbacks, options, extData);
  682.     } 
  683.     
  684.     else if (options == kLanguageIndent) {
  685.         
  686.         _languageHandleIndent(extData);
  687.     }
  688.     
  689.     else if (options <= kLanguageIncludes) {
  690.         
  691.         /*
  692.          * Now parse the file, returning a series of valid return token types:
  693.          *
  694.          *        kFunction
  695.          *         kKeyword
  696.          *         kComment
  697.          *        kCustomKeyword
  698.          */
  699.             
  700.         while ((token = _languageGetNextToken()) != nil) {
  701.         
  702.             type = token->type;
  703.             
  704.             if (type == kSymbolReservedWord) {
  705.             
  706.                 token->majorType = kKeyword;
  707.                 ptr                 = token->string;
  708.                 
  709.                 if (options == kLanguageParse)
  710.                     extTokenReturn(callbacks, token);
  711.  
  712.                 if (ptr[1] == 'o' && options != kLanguageIncludes) { /* on */
  713.                         
  714.                     while ((token = _languageGetNextToken()) != nil) {
  715.                         if (token->type != kSymbolWhiteSpace)
  716.                             break;
  717.                     }
  718.                 
  719.                     if (token->type != kSymbolReservedWord) {
  720.                         token->majorType       = kFunction;
  721.                         token->commentLocation = -1;
  722.                         extTokenReturn(callbacks, token);
  723.                     }
  724.                     else
  725.                         token->majorType = kKeyword;
  726.                 }
  727.  
  728.             }
  729.         
  730.             else if (type == kSymbolCustomWord) {
  731.                 token->majorType = kCustomKeyword;
  732.             }
  733.  
  734.             else if (type == kSymbolComment)
  735.                 token->majorType = kComment;
  736.             
  737.             /*
  738.              * Only return a token if it's a interesting token, and
  739.              * if we are doing a full parse
  740.              */
  741.              
  742.             if (token->majorType >= 0 && options == kLanguageParse)
  743.                 extTokenReturn(callbacks, token);
  744.         }
  745.     }
  746.     
  747.     /*
  748.      * Clean up after ourselves
  749.      */
  750.  
  751.     languageDone(&globals, callbacks);
  752.     
  753.     SetA4(saved_a4);
  754. }
  755.